package com.jrx.anytxn.param.service.cardRoll.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.jrx.anytxn.common.data.TxnRespCode;
import com.jrx.anytxn.common.exception.TxnBizException;
import com.jrx.anytxn.common.exception.TxnException;
import com.jrx.anytxn.common.uitl.BeanMapping;
import com.jrx.anytxn.common.uitl.DateUtils;
import com.jrx.anytxn.i18n.response.TxnPage;
import com.jrx.anytxn.number.exception.SegmentException;
import com.jrx.anytxn.number.service.ISegmentService;
import com.jrx.anytxn.param.constant.Constant;
import com.jrx.anytxn.param.constant.ErrorMsgConstant;
import com.jrx.anytxn.param.entity.PrCardRollDetailInfo;
import com.jrx.anytxn.param.entity.PrCardRollInfo;
import com.jrx.anytxn.param.entity.PrCardRollToleadRecord;
import com.jrx.anytxn.param.mapper.base.PrCardRollDetailInfoMapper;
import com.jrx.anytxn.param.mapper.base.PrCardRollInfoMapper;
import com.jrx.anytxn.param.mapper.base.PrCardRollToleadRecordMapper;
import com.jrx.anytxn.param.service.cardRoll.ICardRollService;
import com.jrx.anytxn.redisson.service.RedissonLockService;
import com.jrx.anytxn.redisson.util.LockType;
import org.redisson.api.RLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 卡券管理 业务接口实现
 *
 * @author : SGtai
 * 2023/08/29
 */
@Service
public class CardRollServiceImpl implements ICardRollService {

    private static final Logger logger = LoggerFactory.getLogger(CardRollServiceImpl.class);

    @Resource
    private PrCardRollInfoMapper prCardRollInfoMapper;

    @Resource
    private PrCardRollDetailInfoMapper prCardRollDetailInfoMapper;

    @Resource
    private PrCardRollToleadRecordMapper prCardRollToleadRecordMapper;

    @Autowired
    private ISegmentService segmentService;

    @Autowired
    private RedissonLockService redissonLockService;

    @Override
    public TxnPage<PrCardRollInfo> findInfoPageByTenantId(Integer pageNum, Integer pageSize, PrCardRollInfo prCardRollInfo) throws TxnException {
        logger.info("卡券列表分页查询参数：{}", JSONObject.toJSONString(prCardRollInfo));
        Page<PrCardRollInfo> page = PageHelper.startPage(pageNum, pageSize, Constant.ORDER_BY_SORT);
        List<PrCardRollInfo> prCardRollInfoList = prCardRollInfoMapper.queryByCardRollInfo(prCardRollInfo);

        List<PrCardRollInfo> res = BeanMapping.copyList(prCardRollInfoList, PrCardRollInfo.class);
        return new TxnPage<>(pageNum, pageSize, page.getTotal(), res);
    }

    @Override
    public TxnPage<PrCardRollDetailInfo> findDetailPageByTenantId(Integer pageNum, Integer pageSize, PrCardRollDetailInfo rollDetailInfo) throws TxnException {
        logger.info("卡券明细列表分页查询参数：{}", JSONObject.toJSONString(rollDetailInfo));
        Page<PrCardRollDetailInfo> page = PageHelper.startPage(pageNum, pageSize, Constant.ORDER_BY_SORT);
        List<PrCardRollDetailInfo> prCardRollInfoList = prCardRollDetailInfoMapper.queryByCardRollDetailInfo(rollDetailInfo);

        List<PrCardRollDetailInfo> res = BeanMapping.copyList(prCardRollInfoList, PrCardRollDetailInfo.class);
        return new TxnPage<>(pageNum, pageSize, page.getTotal(), res);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public PrCardRollInfo modifyCardRollInfo(PrCardRollInfo prCardRollInfo) {
        Assert.hasLength(prCardRollInfo.getTenantId(), "租户号不能为空");
        Assert.hasLength(String.valueOf(prCardRollInfo.getCardRollId()), "卡卷ID不能为空");

        PrCardRollInfo cardRollInfo = prCardRollInfoMapper.selectByCardRollId(prCardRollInfo.getTenantId(), prCardRollInfo.getCardRollId());
        // 主键存在的信息才需要修改
        if (!StringUtils.isEmpty(cardRollInfo)) {
            //修改 pr_card_roll_info 卡券基本信息
            prCardRollInfo.setCreateTime(new Date());
            prCardRollInfo.setUpdateTime(new Date());
            prCardRollInfo.setUpdateBy(prCardRollInfo.getUpdateBy());
            prCardRollInfo.setRecordVersionNumber(prCardRollInfo.getRecordVersionNumber() + 1);
            prCardRollInfoMapper.updateByPrCardRollInfo(prCardRollInfo);
        } else {
            try {
                //新增 pr_card_roll_info 卡券基本信息
                cardRollInfo = new PrCardRollInfo();
                BeanUtils.copyProperties(prCardRollInfo, cardRollInfo);
                cardRollInfo.setTenantId(prCardRollInfo.getTenantId());
                cardRollInfo.setId(segmentService.getId(Constant.PR_BANK_INST_INFO));
                prCardRollInfoMapper.insertSelective(prCardRollInfo);
            } catch (Exception e) {
                logger.warn("插入记录表失败：{}", e.getMessage());
                e.printStackTrace();
            }
        }
        return cardRollInfo;
    }

    @Override
    public Boolean removeByTenIdAndCardRollId(String cardRollId,String tenantId) throws TxnException {
        Assert.hasLength(cardRollId, "卡卷ID不能为空");
        Assert.hasLength(tenantId, "租户号不能为空");
        PrCardRollInfo queryObj = new PrCardRollInfo();
        queryObj.setTenantId(tenantId);
        queryObj.setCardRollId(cardRollId);
        List<PrCardRollInfo> cardRollInfos = prCardRollInfoMapper.queryByCardRollInfo(queryObj);
        if (!CollectionUtils.isEmpty(cardRollInfos)){
            if (cardRollInfos.get(0).getResidueRepertory() != cardRollInfos.get(0).getStoreQuantity()){
                throw new TxnException("删除出错了");
            }
        }
        prCardRollInfoMapper.deleteByTenIdAndCardRollId(tenantId, cardRollId);
        prCardRollDetailInfoMapper.deleteByTenIdAndCardRollId(tenantId, cardRollId);
        return true;
    }


    /**
     * 保存信息
     *
     * @param list
     * @param tenantId
     * @param operator
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public PrCardRollInfo batchSaveQrcodes(List<List<String>> list, String tenantId, String operator, String cardRollId,StringBuffer tips) throws TxnException {
        if (org.apache.commons.collections.CollectionUtils.isNotEmpty(list)) {
            Assert.hasLength(tenantId, "租户号不能为空");
            Assert.hasLength(cardRollId, "卡券ID不能为空");
            AtomicInteger cardRollNum = new AtomicInteger();
            AtomicInteger lineInt = new AtomicInteger();
            lineInt.set(1);
            List<Integer> errLineList = new ArrayList<>();
            list.forEach(fields -> {
                try {
                    lineInt.addAndGet(1);
                    if (fields.size() == 2) {
                        //新增 pr_card_roll_detail_info  卡券明细信息
                        PrCardRollDetailInfo rollDetailInfo = new PrCardRollDetailInfo();
                        rollDetailInfo.setPassWord(fields.get(1)); // 密码
                        rollDetailInfo.setCardRollId(cardRollId);  //卡卷   ID
                        rollDetailInfo.setTenantId(tenantId);
                        List<PrCardRollDetailInfo> prCardRollDetailInfoList = prCardRollDetailInfoMapper.queryByCardRollDetailInfo(rollDetailInfo);
                        if (CollectionUtils.isEmpty(prCardRollDetailInfoList)) {
                            rollDetailInfo.setTenantId(tenantId);
                            rollDetailInfo.setUpdateBy(operator);
                            rollDetailInfo.setCardNumber(fields.get(0));
                            rollDetailInfo.setReceiveState("0");
                            try {
                                rollDetailInfo.setId(segmentService.getId(Constant.PR_BANK_INST_INFO));
                            } catch (SegmentException e) {
                                logger.error("主键生成错误", e);
                                throw new TxnException(ErrorMsgConstant.ERROR_ID);
                            }
                            prCardRollDetailInfoMapper.insertSelective(rollDetailInfo);
                            cardRollNum.addAndGet(1);
                        }
                    }else{
                        errLineList.add(lineInt.get());
                    }
                } catch (Exception e) {
                    logger.warn("插入卡券明细信息失败：{}", e.getMessage());
                    errLineList.add(lineInt.get());
                    return;
                }
            });

            if (cardRollNum.get() == 0){
                throw new TxnException("已存在导入信息");
            }

            if (!CollectionUtils.isEmpty(errLineList)){
                tips.append("导入失败行数：");
                for (Integer err : errLineList){
                    tips.append(err+",");
                }
            }

            try {
                //新增 pr_card_roll_tolead_record  卡券导入记录
                PrCardRollToleadRecord cardRollToleadRecord = new PrCardRollToleadRecord();
                cardRollToleadRecord.setTenantId(tenantId);
                cardRollToleadRecord.setUpdateBy(operator);
                cardRollToleadRecord.setCardRollId(cardRollId);
                cardRollToleadRecord.setThisQuantityNum(cardRollNum.get());
                try {
                    cardRollToleadRecord.setId(segmentService.getId(Constant.PR_BANK_INST_INFO));
                } catch (SegmentException e) {
                    logger.error("主键生成错误", e);
                    throw new TxnException(ErrorMsgConstant.ERROR_ID);
                }
                prCardRollToleadRecordMapper.insertSelective(cardRollToleadRecord);

                PrCardRollInfo queryObj = new PrCardRollInfo();
                queryObj.setTenantId(tenantId);
                queryObj.setCardRollId(cardRollId);
                List<PrCardRollInfo> cardRollInfos = prCardRollInfoMapper.queryByCardRollInfo(queryObj);
                logger.info("卡券基本信息查询参数：{}", JSONObject.toJSONString(cardRollInfos));
                PrCardRollInfo prCardRollInfo = new PrCardRollInfo();
                if (!CollectionUtils.isEmpty(cardRollInfos)){
                    //修改 pr_card_roll_info 卡券基本信息
                    prCardRollInfo = cardRollInfos.get(0);
                    prCardRollInfo.setUpdateBy(operator);
                    prCardRollInfo.setStoreQuantity(prCardRollInfo.getStoreQuantity()+cardRollNum.get());
                    prCardRollInfo.setResidueRepertory(prCardRollInfo.getResidueRepertory()+ cardRollNum.get());
                    prCardRollInfo.setCreateTime(new Date());
                    prCardRollInfo.setUpdateTime(new Date());
                    logger.info("卡券基本信息修改库存参数：{}", JSONObject.toJSONString(prCardRollInfo));
                    prCardRollInfoMapper.updateByPrCardRollInfo(prCardRollInfo);//修改库存
                }else{
                    //新增 pr_card_roll_info 卡券基本信息
                    prCardRollInfo.setTenantId(tenantId);
                    prCardRollInfo.setUpdateBy(operator);
                    prCardRollInfo.setCardRollId(cardRollId);
                    prCardRollInfo.setInvokeState("1");
                    prCardRollInfo.setStoreQuantity(cardRollNum.get());
                    prCardRollInfo.setResidueRepertory(cardRollNum.get());
                    try {
                        prCardRollInfo.setId(segmentService.getId(Constant.PR_BANK_INST_INFO));
                    } catch (SegmentException e) {
                        logger.error("主键生成错误", e);
                        throw new TxnException(ErrorMsgConstant.ERROR_ID);
                    }
                    logger.info("卡券基本信息新增参数：{}", JSONObject.toJSONString(prCardRollInfo));
                    prCardRollInfoMapper.insertSelective(prCardRollInfo);
                }
                return prCardRollInfo;
            } catch (Exception e) {
                logger.warn("插入记录表失败：{}", e.getMessage());
                throw new TxnException("插入记录表失败："+e.getMessage());
            }
        }
        return null;
    }

    @Override
    public TxnPage<PrCardRollToleadRecord> findToleadRecordByTenantId(Integer pageNum, Integer pageSize, PrCardRollToleadRecord prCardRollToleadRecord) throws TxnException {
        logger.info("卡券导入记录分页查询参数：{}", JSONObject.toJSONString(prCardRollToleadRecord));
        Page<PrCardRollToleadRecord> page = PageHelper.startPage(pageNum, pageSize, Constant.ORDER_BY_SORT);
        List<PrCardRollToleadRecord> prCardRollToleadRecords = prCardRollToleadRecordMapper.queryByCardRollToleadRecord(prCardRollToleadRecord);

        List<PrCardRollToleadRecord> res = BeanMapping.copyList(prCardRollToleadRecords, PrCardRollToleadRecord.class);
        return new TxnPage<>(pageNum, pageSize, page.getTotal(), res);
    }

    @Override
    public PrCardRollInfo getCardRollInfoById(String tenantId, String id) throws TxnException {
        Assert.hasLength(tenantId, "租户号不能为空");
        Assert.hasLength(id, "主键不能为空");

        PrCardRollInfo prCardRollInfo = new PrCardRollInfo();
        prCardRollInfo.setTenantId(tenantId);
        prCardRollInfo.setId(Long.valueOf(id));

        List<PrCardRollInfo> prCardRollInfoList = prCardRollInfoMapper.queryByCardRollInfo(prCardRollInfo);
        if (!CollectionUtils.isEmpty(prCardRollInfoList)) {
            return prCardRollInfoList.get(0);
        }
        return null;
    }

    @Override
    public PrCardRollInfo addCardRollInfo(PrCardRollInfo prCardRollInfo) throws TxnException {
        Assert.hasLength(prCardRollInfo.getTenantId(), "租户号不能为空");

        if (!StringUtils.isEmpty(prCardRollInfo.getCardRollId())) {
            PrCardRollInfo queryObj = new PrCardRollInfo();
            queryObj.setTenantId(prCardRollInfo.getTenantId());
            queryObj.setCardRollId(prCardRollInfo.getCardRollId());

            List<PrCardRollInfo> cardRollInfos = prCardRollInfoMapper.queryByCardRollInfo(queryObj);
            if (!CollectionUtils.isEmpty(cardRollInfos)) {
                logger.warn("该卡券id信息已存在，cardRollId:{}", prCardRollInfo.getCardRollId());
                throw new RuntimeException("该卡券id信息已存在");
            }
        }

        long id = 0;
        try {
            id = segmentService.getId(Constant.PR_BANK_INST_INFO);
            prCardRollInfo.setId(id);
        } catch (SegmentException e) {
            logger.error("主键生成错误", e);
            throw new TxnException(ErrorMsgConstant.ERROR_ID);
        }
        //若未传卡券id，则生成
        if (StringUtils.isEmpty(prCardRollInfo.getCardRollId())) {
            prCardRollInfo.setCardRollId(String.valueOf(id));
        }

        //初始化入库数量与剩余数量
        prCardRollInfo.setResidueRepertory(0);
        prCardRollInfo.setStoreQuantity(0);

        prCardRollInfoMapper.insertSelective(prCardRollInfo);
        return prCardRollInfo;
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public PrCardRollDetailInfo rightsPassExtract(PrCardRollDetailInfo prCardRollDetailInfo)throws TxnException {
        Assert.hasLength(prCardRollDetailInfo.getSceneId(), "场景订单ID不能为空");
        Assert.hasLength(String.valueOf(prCardRollDetailInfo.getCardRollId()), "权益ID不能为空");
        Assert.hasLength(prCardRollDetailInfo.getReceivePhone(), "领用手机号不能为空");
        logger.info("卡密提取参数：{}", JSONObject.toJSONString(prCardRollDetailInfo));
        PrCardRollInfo queryObj = new PrCardRollInfo();
        queryObj.setTenantId(prCardRollDetailInfo.getTenantId());
        queryObj.setCardRollId(prCardRollDetailInfo.getCardRollId());

        List<PrCardRollInfo> cardRollInfos = prCardRollInfoMapper.queryByCardRollInfo(queryObj);
        String lockKey = String.format(String.valueOf(prCardRollDetailInfo.getCardRollId()), prCardRollDetailInfo.getTenantId());
        RLock rlock = redissonLockService.getRLock(lockKey, LockType.REENTRANT_LOCK);
        try{
            if (!CollectionUtils.isEmpty(cardRollInfos)) {
                boolean lockFirst = rlock.tryLock(0, 10, TimeUnit.SECONDS);
                logger.info("当前cardRollId:{} 尝试拿锁，{}", prCardRollDetailInfo.getCardRollId(), lockFirst);
                if (!lockFirst) {
                    logger.info("当前人数太多,请稍后重试");
                    throw new TxnBizException(TxnRespCode.TRY_LOCK_FAIL);
                }
                queryObj = cardRollInfos.get(0);
                if ("0".equals(queryObj.getInvokeState())){
                    throw new TxnBizException(TxnRespCode.COUPON_NOT_ENABLE);
                }
                Integer storeQuantity = queryObj.getResidueRepertory();
                if(storeQuantity == null || storeQuantity <= 0){
                    logger.info("权益id:{} 库存不足，为：{}", prCardRollDetailInfo.getCardRollId(),storeQuantity);
                    throw new TxnBizException(TxnRespCode.RIGHTS_AND_INTEREST_STOCK_DEFICIENT);
                }

                //时间校验，有效期失效期兼容当天
                String nowStr = DateUtils.format(new Date(), "yyyy-MM-dd");
                String expirationDate = queryObj.getExpireDate();
                String effectiveDate = queryObj.getEffectiveDate();
                boolean valid = nowStr.compareTo(effectiveDate) >= 0 && expirationDate.compareTo(nowStr) >= 0;
                if (!valid) {
                    logger.info("该卡券未在有效期内，卡券id：{}", queryObj.getCardRollId());
                    throw new TxnBizException("权益未在生效日期内，请兑换其他权益");
                }

                List<PrCardRollDetailInfo> rollDetailInfos = prCardRollDetailInfoMapper.queryBySceneIdAndCardRollId(prCardRollDetailInfo);
                if (!CollectionUtils.isEmpty(rollDetailInfos)) {
                    if ("1".equals(rollDetailInfos.get(0).getReceiveState())){
                        logger.info("卡卷已被使用：{}", prCardRollDetailInfo.getCardRollId());
                        throw new TxnBizException(TxnRespCode.CUSTOMER_RIGHT_ALREADY_USED);
                    }
                }
                PrCardRollDetailInfo rollDetailInfo = new PrCardRollDetailInfo();
                rollDetailInfo.setCardRollId(prCardRollDetailInfo.getCardRollId());
                rollDetailInfo.setTenantId(prCardRollDetailInfo.getTenantId());
                rollDetailInfo.setReceiveState("0");
                List<PrCardRollDetailInfo> rollDetailInfos1 = prCardRollDetailInfoMapper.queryByCardRollDetailInfo(rollDetailInfo);
                if (CollectionUtils.isEmpty(rollDetailInfos1)){
                    logger.info("卡卷明细未找到：{}", prCardRollDetailInfo.getCardRollId());
                    throw new TxnBizException(TxnRespCode.NO_DATA);
                }
                prCardRollDetailInfo.setReceiveState("1");
                prCardRollDetailInfo.setRecordVersionNumber(rollDetailInfos1.get(0).getRecordVersionNumber());
                prCardRollDetailInfo.setUpdateTime(new Date());
                prCardRollDetailInfo.setUpdateBy(prCardRollDetailInfo.getUpdateBy());
                prCardRollDetailInfo.setId(rollDetailInfos1.get(0).getId());
                prCardRollDetailInfo.setCardNumber(rollDetailInfos1.get(0).getCardNumber());
                prCardRollDetailInfo.setPassWord(rollDetailInfos1.get(0).getPassWord());//获取卡密
                prCardRollDetailInfoMapper.updatePrCardRollDetailInfo(prCardRollDetailInfo);//更新领用状态场景ID信息
                queryObj.setResidueRepertory(queryObj.getResidueRepertory()-1);
                prCardRollInfoMapper.updateByPrCardRollInfo(queryObj);//修改库存
            } else {
                logger.info("卡卷基本明细未找到：{}", prCardRollDetailInfo.getCardRollId());
                throw new TxnBizException(TxnRespCode.NO_DATA);
            }
        } catch (TxnBizException bizException) {
            throw bizException;
        } catch (Exception e) {
            throw new TxnBizException(TxnRespCode.ERROR.getCode(), e.getMessage());
        } finally {
            if (rlock.isLocked() && rlock.isHeldByCurrentThread()) {
                rlock.unlock();
            }
        }
        return prCardRollDetailInfo;
    }
}
